//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ListBindingSitePredictionWeighted.h"
#include "ListBindingSitePrediction.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fstream>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define MAX_SIZE 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace BindingSitePredictionWeighted {

  bool EqualWeightedPatternSeq (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Type()->Out(), "Seq") && !strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;
    
  }
  
  bool EqualWeightedPatternCH (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Type()->Out(), "CH") && !strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;
    
  }
  
  bool EqualWeightedPatternPH (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Type()->Out(), "PH") && !strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;
    
  }
  
  bool EqualWeightedPatternSS (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Type()->Out(), "SS") && !strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;
    
  }
  
  bool EqualWeightedPatternMT (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Type()->Out(), "MT") && !strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;
    
  }
  
}  
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted::ListBindingSitePredictionWeighted () {

  this->filenameXMLModels      = new String ();
  this->scheme                 = new String ();
  this->xmlModels              = new ModelsSummaryByLigand ();
  this->weights                = new MethodWeighted ();
  
  this->toString               = new String ();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted::ListBindingSitePredictionWeighted (const ListBindingSitePredictionWeighted& listBindingSitePredictionWeighted) {

  this->filenameXMLModels      = new String (listBindingSitePredictionWeighted.filenameXMLModels);
  this->scheme                 = new String (listBindingSitePredictionWeighted.scheme);
  this->xmlModels              = new ModelsSummaryByLigand (listBindingSitePredictionWeighted.xmlModels);
  this->weights                = new MethodWeighted (listBindingSitePredictionWeighted.weights);

  this->toString               = new String (listBindingSitePredictionWeighted.toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted::ListBindingSitePredictionWeighted (const ListBindingSitePredictionWeighted* listBindingSitePredictionWeighted) {

  this->filenameXMLModels      = new String (listBindingSitePredictionWeighted->filenameXMLModels);
  this->scheme                 = new String (listBindingSitePredictionWeighted->scheme);
  this->xmlModels              = new ModelsSummaryByLigand (listBindingSitePredictionWeighted->xmlModels);
  this->weights                = new MethodWeighted (listBindingSitePredictionWeighted->weights);

  this->toString               = new String (listBindingSitePredictionWeighted->toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted::~ListBindingSitePredictionWeighted () {

  if (this->filenameXMLModels)   delete this->filenameXMLModels;
  if (this->scheme)              delete this->scheme;
  if (this->xmlModels)           delete this->xmlModels;
  if (this->weights)             delete this->weights;
  if (this->toString)            delete this->toString;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListBindingSitePredictionWeighted::FilenameXMLModels (String* filenameXMLModels) {

  if (filenameXMLModels)
    *(this->filenameXMLModels) = *filenameXMLModels;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListBindingSitePredictionWeighted::Scheme (String* scheme) {

  if (scheme)
    *(this->scheme) = *scheme;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListBindingSitePredictionWeighted::XMLModels (ModelsSummaryByLigand* xmlModels) {

  if (xmlModels)
    *(this->xmlModels) = *xmlModels;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListBindingSitePredictionWeighted::Weights (MethodWeighted* weights) {

  if (weights)
    *(this->weights) = *weights;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListBindingSitePredictionWeighted::FilenameXMLModels (void) {

  return this->filenameXMLModels;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListBindingSitePredictionWeighted::Scheme (void) {

  return this->scheme;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelsSummaryByLigand* ListBindingSitePredictionWeighted::XMLModels (void) {

  return this->xmlModels;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
MethodWeighted* ListBindingSitePredictionWeighted::Weights (void) {

  return this->weights;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListBindingSitePredictionWeighted::LoadData (void) {

  if (!this->filenameXMLModels || !this->filenameXMLModels->Length())
    return false;
  
  if (!ListBindingSitePrediction::LoadData()) 
    return false;
  
  this->xmlModels->FilenameIn(this->filenameXMLModels);
  
  if (!this->xmlModels->LoadXMLFile())
    return false;
  
  if (!this->LoadWeight())
    return false;
  
  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListBindingSitePredictionWeighted::LoadWeight (void) {
  
  if (!this->scheme || !this->scheme->Length())
    return false;
  
  int position = 0;

  this->xmlModels->Models()->SetInitial();
  while (this->xmlModels->Models()->SetNext()) {
    if (!strcmp(this->xmlModels->Models()->GetCurrent()->Scheme()->Out(), this->scheme->Out()))
      break;
    position++;
  }

  if (position == this->xmlModels->Models()->Length())
    return false;
  else if (!this->weights->LoadData(this->xmlModels->Models()->Get(position)->Model()))
    return false;

  if (!this->weights->Patterns()->Length())
    return false;
  
  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListBindingSitePredictionWeighted::PredictBindingSiteByTypeWeighted (String* type, int scoreType) {

  if (!this->filenamePatterns || !this->filenamePatterns->Length() ||
      !this->weights          || !this->weights->Patterns()        || !this->weights->Patterns()->Length())
    return false;
  
  this->listPatterns->Namefile(this->filenamePatterns);
  if (!this->listPatterns->LoadData())
    return false;

  if (!this->fastaProfile || !this->fastaProfile->ListCathDomainProfile()  || !this->fastaProfile->ListCathDomainProfile()->Length() || 
      !this->listPatterns || !this->listPatterns->ListGroupPrattPatterns() || !this->listPatterns->ListGroupPrattPatterns()->Length())
    return false;

  bool condCounterExtendedPatterns = false;
  long counterExtendedPatterns     = 0;

  this->fastaProfile->ListCathDomainProfile()->SetInitial();
  while (this->fastaProfile->ListCathDomainProfile()->SetNext()) {

    CathFASTAProfile*            currentCathFASTAProfile           = this->fastaProfile->ListCathDomainProfile()->GetCurrent();
    PredictBindingSiteByPattern* searchPredictBindingSiteByPattern = this->predictionsBS->FirstOcurrence(BindingSitePrediction::EqualHeader, currentCathFASTAProfile->ToStringHeader());

    if (!searchPredictBindingSiteByPattern) continue;

    String* sequence     = NULL;
    float*  scorePointer = NULL;

    if      (*(type) == "AA") { sequence = currentCathFASTAProfile->Sequence();              scorePointer = searchPredictBindingSiteByPattern->ScoreAA(); }
    else if (*(type) == "CH") { sequence = currentCathFASTAProfile->ResiduesClassChemical(); scorePointer = searchPredictBindingSiteByPattern->ScoreCH(); }
    else if (*(type) == "PH") { sequence = currentCathFASTAProfile->ResiduesClassPhysical(); scorePointer = searchPredictBindingSiteByPattern->ScorePH(); }
    else if (*(type) == "SS") { sequence = currentCathFASTAProfile->SecondaryStructureP();   scorePointer = searchPredictBindingSiteByPattern->ScoreSS(); }
    else if (*(type) == "MT") { sequence = currentCathFASTAProfile->ResiduesMT();            scorePointer = searchPredictBindingSiteByPattern->ScoreMT(); }

    this->listPatterns->ListGroupPrattPatterns()->SetInitial();
    while (this->listPatterns->ListGroupPrattPatterns()->SetNext()) {
      
      Pratt2Patterns* currentPratt2Patterns = this->listPatterns->ListGroupPrattPatterns()->GetCurrent();
      
      currentPratt2Patterns->Patterns()->SetInitial();
      while (currentPratt2Patterns->Patterns()->SetNext()) {
        
        PatternRecord*        currentPatternRecord = currentPratt2Patterns->Patterns()->GetCurrent();
        String*               pattern              = currentPatternRecord->Pattern();
        SearchPrositePattern* searchPrositePattern = new SearchPrositePattern ();
        PatternWeight*        currentPatternWeight = NULL;
        
        if      (*(type) == "AA") { currentPatternWeight = this->weights->Patterns()->FirstOcurrence(BindingSitePredictionWeighted::EqualWeightedPatternSeq, pattern); }
        else if (*(type) == "CH") { currentPatternWeight = this->weights->Patterns()->FirstOcurrence(BindingSitePredictionWeighted::EqualWeightedPatternCH,  pattern); }
        else if (*(type) == "PH") { currentPatternWeight = this->weights->Patterns()->FirstOcurrence(BindingSitePredictionWeighted::EqualWeightedPatternPH,  pattern); }
        else if (*(type) == "SS") { currentPatternWeight = this->weights->Patterns()->FirstOcurrence(BindingSitePredictionWeighted::EqualWeightedPatternSS,  pattern); }
        else if (*(type) == "MT") { currentPatternWeight = this->weights->Patterns()->FirstOcurrence(BindingSitePredictionWeighted::EqualWeightedPatternMT,  pattern); }
        
        if (!currentPatternWeight) 
          continue;

        searchPrositePattern->SearchPattern(sequence, pattern);    
        
        if (TYPE_PATTERN_COUNT == PATTERN_EXTENDED && !condCounterExtendedPatterns)
          counterExtendedPatterns += searchPrositePattern->ExtendedPattern()->Length();
        else if (TYPE_PATTERN_COUNT == PATTERN_COMPACT && !condCounterExtendedPatterns) 
          counterExtendedPatterns++;
        
        searchPrositePattern->Segments()->SetInitial();
        searchPrositePattern->Positions()->SetInitial();
        while (searchPrositePattern->Segments()->SetNext() && searchPrositePattern->Positions()->SetNext())
          for (int i = *(searchPrositePattern->Positions()->GetCurrent()); 
                   i < (*(searchPrositePattern->Positions()->GetCurrent()) + searchPrositePattern->Segments()->GetCurrent()->Length()); 
                   i++) 
            (scorePointer[i]) += -currentPatternWeight->Weight();
            //(scorePointer[i]) += ((currentPatternWeight->Weight() > 0)?currentPatternWeight->Weight():(-currentPatternWeight->Weight()));

      }
      
    }

    float maxValue = 0;

    for (long i = 0; i < searchPredictBindingSiteByPattern->Sequence()->Length(); i++)
      if (scorePointer[i] > maxValue)
        maxValue = scorePointer[i];

    for (long i = 0; i < searchPredictBindingSiteByPattern->Sequence()->Length(); i++) {
      if      (scoreType == SCORE_NORMAL)     scorePointer[i] = scorePointer[i] / ((counterExtendedPatterns)?counterExtendedPatterns:1);
      else if (scoreType == SCORE_CUMULATIVE) scorePointer[i] = scorePointer[i];
      else if (scoreType == SCORE_NORMALIZED) scorePointer[i] = scorePointer[i] / ((maxValue)?maxValue:1);
    }

    condCounterExtendedPatterns = true;

  }

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListBindingSitePredictionWeighted::PredictBindingSiteWeighted (String* namefileAA, String* namefileCH, String* namefilePH, String* namefileSS, String* namefileMT, int scoreType) {

  String type;
  int    considered = 0;

  if (namefileAA && *(namefileAA) != "NULL") {
    this->filenamePatterns->In(namefileAA);
    type.In("AA");
    if (!this->PredictBindingSiteByTypeWeighted(&type, scoreType))
      return false;
    considered++;
  }

  if (namefileCH && *(namefileCH) != "NULL") {
    this->filenamePatterns->In(namefileCH);
    type.In("CH");
    if (!this->PredictBindingSiteByTypeWeighted(&type, scoreType))
      return false;
    considered++;
  }

  if (namefilePH && *(namefilePH) != "NULL") {
    this->filenamePatterns->In(namefilePH);
    type.In("PH");
    if (!this->PredictBindingSiteByTypeWeighted(&type, scoreType))
      return false;
    considered++;
  }

  if (namefileSS && *(namefileSS) != "NULL") {
    this->filenamePatterns->In(namefileSS);
    type.In("SS");
    if (!this->PredictBindingSiteByTypeWeighted(&type, scoreType))
      return false;
    considered++;
  }

  if (namefileMT && *(namefileMT) != "NULL") {
    this->filenamePatterns->In(namefileMT);
    type.In("MT");
    if (!this->PredictBindingSiteByTypeWeighted(&type, scoreType))
      return false;
    considered++;
  }
  
  this->FillCumulativePredictionBindingSite(1, 1, 1, 1, 1, SCORE_NORMALIZED, considered, BY_PRODUCT);

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListBindingSitePredictionWeighted::PlotWeightHistogram (String* filenameHistogram, String* namePlot) {
  
  if (!this->xmlModels   || !this->xmlModels->Models()->Length() ||
      !this->weights     || !this->weights->Patterns()->Length() ||
      !filenameHistogram || !filenameHistogram->Length())
    return false;
  
  char           cmd [MAX_SIZE];
  gnuplot_ctrl*  plot           = gnuplot_init();

  double*        weightsModel   = new double [weights->Patterns()->Length()]; 
  int            position       = 0;

  weights->Patterns()->SetInitial();
  while (weights->Patterns()->SetNext()) 
    if (strcmp(weights->Patterns()->GetCurrent()->Type()->Out(), "Correction") != 0)
      weightsModel[position++] = weights->Patterns()->GetCurrent()->Weight();

  if (!position) {
    gnuplot_set_xrange (plot, 0, 5000); 
    weightsModel = new double [1];
    weightsModel[position++] = 0;
  }

  gnuplot_saveplotPNG(plot, filenameHistogram->Out(), 7, 600, 600);
    
  sprintf(cmd, "unset key\0");
  gnuplot_cmd(plot, cmd);

  sprintf(cmd, "set format x \"%%%%02.2f\"\0");
  gnuplot_cmd(plot, cmd);

  gnuplot_set_xlabel(plot, "Weight", "font \"FreeMono-Bold, 10\" tc rgb \"black\"");
  gnuplot_set_ylabel(plot, "Frequency", "font \"FreeMono-Bold, 10\" tc rgb \"black\"");

  gnuplot_plot_histogram(plot, weightsModel, weights->Patterns()->Length(), 50, namePlot->Out());   

  gnuplot_close(plot);

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted ListBindingSitePredictionWeighted::operator= (const ListBindingSitePredictionWeighted& listBindingSitePredictionWeighted) {

  *(this->filenameXMLModels) = *(listBindingSitePredictionWeighted.filenameXMLModels);
  *(this->weights)           = *(listBindingSitePredictionWeighted.weights);
  *(this->xmlModels)         = *(listBindingSitePredictionWeighted.xmlModels);
  *(this->scheme)            = *(listBindingSitePredictionWeighted.scheme);
  *(this->toString)          = *(listBindingSitePredictionWeighted.toString);

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
